﻿using System;
using PacMan3D.Utils;
using PacMan3D.Objects;
using System.Collections.Generic;
using Tao.OpenGl;
using Tao.FreeGlut;
using PacMan3D.Camera;
using PacMan3D.IO;
using PacMan3D;
using PacMan3D.Physics;
using System.Threading;
using PacMan3D.Sounds;
using System.Windows.Forms;

namespace PacMan3D.Windows
{
    public class GameWindow : IWindow
    {
        private bool QuitGame;

        private SkySphere SkySphere;
        private Fog Fog;
        private Maze Maze;
        private Axis Axis;
        private Light Light;
        private Banner Banner;
        private CameraViewer CameraViewer;
        private CollisionEngine PhysicEngine;
        private int RefreshTime = 30;

        public GameWindow()
        {
            this.QuitGame = false;

            this.Maze = new Maze();

            try
            {
                this.Maze.LoadMap(Constants.RES_MAP_FILE);
            }
            catch (Exception e)
            {
                MessageBox.Show("Could not load the Maze: " + e.Message);
                Window.Instance().ExitGame();
            }

            this.Banner = new Banner(this.Maze);

            this.CameraViewer = new CameraViewer(this.Maze);

            this.PhysicEngine = new CollisionEngine(this.Maze);

            this.Fog = new Fog();

            this.SkySphere = new SkySphere(this.Maze.Platform.GetCentralPoint(), (int)(120 * this.Maze.BlockSize));

            // To Remove ...
            this.Axis = new Axis(new Size(Window.Instance().Height));

            // To Update ...
            this.Light = new Light(this.Maze);

            this.Maze.CalculateShadowMatrix(this.Light.GetPosition());

            Glut.glutTimerFunc(RefreshTime, new Glut.TimerCallback(TimerHandler), 0);
        }

        #region IWindow Members

        public void DisplayHandler()
        {
            ///
            /// 
            /// 
            SetGlutToEasyMode();

            ///
            /// update sound system
            ///
            SoundController.Instance().Update();

            ///
            /// check for collisions ...
            /// 
            this.PhysicEngine.CheckForCollisios();

            ///
            /// update the perspective camera and the observer ...
            ///
            CameraViewer.Film();

            ///
            /// draw the sky sphere
            /// 
            this.SkySphere.DrawObject();

            ///
            /// draw the axis ...
            ///
            /// this.Axis.DrawObject();

            ///
            /// draw the light ...
            /// 
            this.Light.DrawObject();
            
            /// 
            /// draw the maze objects ...
            /// 
            this.Maze.DrawObjects();

            ///
            /// draw the banner
            ///
            this.Banner.DrawObject();

            Gl.glFlush();

            Glut.glutSwapBuffers();
        }

        public void ReshapeHandler(int width, int height)
        {
            Window.Instance().Width = width;
            Window.Instance().Height = ((height == 0) ? 1 : height);
            Glut.glutPostRedisplay();
        }

        public void KeyboardHandler(byte key, int x, int y)
        {
            switch (key)
            {
                case (int)'x':
                    this.CameraViewer.DecreaseGodPositionX();
                    break;

                case (int)'X':
                    this.CameraViewer.IncreaseGodPositionX();
                    break;

                case (int)'y':
                    this.CameraViewer.DecreaseGodPositionY();
                    break;

                case (int)'Y':
                    this.CameraViewer.IncreaseGodPositionY();
                    break;

                case (int)'v':
                case (int)'V':
                    this.Fog.Disable();
                    this.CameraViewer.ChangeCurrentObserver();
                    if (this.CameraViewer.CurrentObserver == CameraObserver.PacMan)
                    {
                        this.Maze.PacMan.DisableEasyMode();
                    }
                    break;

                case (int)'q':
                case (int)'Q':
                    this.QuitGame = true;
                    return;

                case (int)'F':
                case (int)'f':
                    if (this.CameraViewer.AlowedEnableFog())
                        this.Fog.ChangeStatus();
                    break;

                case (int)'e':
                case (int)'E':
                    if (this.CameraViewer.CurrentObserver != CameraObserver.PacMan)
                    {
                        this.Maze.PacMan.ChangeMode();
                    }
                    break;

                case 27:
                    Window.Instance().ExitGame();
                    break;

                default:
                    break;
            }
            Glut.glutPostRedisplay();
        }

        public void SpecialHandler(int key, int x, int y)
        {
            DirectionType direction;
            switch (key)
            {
                case Glut.GLUT_KEY_LEFT:
                    direction = DirectionType.Left;
                    break;
                case Glut.GLUT_KEY_RIGHT:
                    direction = DirectionType.Right;
                    break;
                case Glut.GLUT_KEY_UP:
                    direction = DirectionType.Up;
                    break;
                case Glut.GLUT_KEY_DOWN:
                    direction = DirectionType.Down;
                    break;
                default:
                    direction = DirectionType.None;
                    break;
            }

            direction = this.CameraViewer.GetRealDirection(direction);

            this.Maze.PacMan.ChangeDirection(direction);

            Glut.glutPostRedisplay();
        }

        private void SetGlutToEasyMode()
        {
            if (this.Maze.PacMan.IsEasyMode)
            {
                Glut.glutIgnoreKeyRepeat(1);
            }
            else
            {
                Glut.glutIgnoreKeyRepeat(0);
            }
        }

        public void SpecialUpHandler(int key, int x, int y) {}

        public void IdleHandler() {}

        public void TimerHandler(int value)
        {
            if (!this.QuitGame)
            {
                this.Maze.AnimeGame(this.CameraViewer.CurrentObserver);

                Glut.glutPostRedisplay();

                if (!this.Maze.GameOver())
                {
                    Glut.glutTimerFunc(this.RefreshTime, TimerHandler, 0);
                }
                else
                {
                    Thread.Sleep(1000);

                    if (this.Maze.IsPacManWinner())
                    {
                        SoundController.Instance().PlaySound(SoundController.SoundEventType.GAME_OVER_WIN_2);
                    }
                    else 
                    {
                        SoundController.Instance().PlaySound(SoundController.SoundEventType.GAME_OVER_LOOSE_2);
                    }
                    Window.Instance().UpdateCurrentMode(Mode.Menu);
                    return;
                }
            }
            else
            {
                Thread.Sleep(1000);
                Window.Instance().UpdateCurrentMode(Mode.Menu);
                return;
            }
        }
        #endregion
    }
}
